<script lang="ts" setup>
import { i18n } from "@/locales";
import { type Editor } from "@/tiptap/vue-3";
import { TextSelection } from "@tiptap/pm/state";
import { Dropdown as VDropdown, vTooltip } from "floating-vue";
import { test } from "linkifyjs";
import { computed, type Component } from "vue";
import MdiLinkVariant from "~icons/mdi/link-variant";

const props = defineProps<{
  editor: Editor;
  isActive: ({ editor }: { editor: Editor }) => boolean;
  visible?: ({ editor }: { editor: Editor }) => boolean;
  icon?: Component;
  title?: string;
  action?: ({ editor }: { editor: Editor }) => void;
}>();

const href = computed({
  get() {
    const attrs = props.editor.getAttributes("link");
    return attrs?.href;
  },
  set(value) {
    props.editor.commands.setLink({
      href: value,
      target: target.value ? "_blank" : "_self",
      rel: rel.value ? "nofollow" : "",
    });
  },
});

const target = computed({
  get() {
    const attrs = props.editor.getAttributes("link");
    return attrs?.target === "_blank";
  },
  set(value) {
    props.editor.commands.setLink({
      href: href.value,
      target: value ? "_blank" : "_self",
      rel: rel.value ? "nofollow" : "",
    });
  },
});

const rel = computed({
  get() {
    const attrs = props.editor.getAttributes("link");
    return attrs?.rel === "nofollow";
  },
  set(value) {
    props.editor.commands.setLink({
      href: href.value,
      target: target.value ? "_blank" : "_self",
      rel: value ? "nofollow" : "",
    });
  },
});

/**
 * Convert the currently selected text when clicking the link
 */
const handleLinkBubbleButton = () => {
  if (props.isActive({ editor: props.editor })) {
    return;
  }
  const { state } = props.editor;
  const { selection } = state;
  const { empty } = selection;

  if (selection instanceof TextSelection) {
    if (empty) {
      return false;
    }
    const { content } = selection.content();
    if (!content || content.childCount !== 1) {
      return false;
    }
    const text = content.firstChild?.textContent;
    if (text && test(text, "url")) {
      props.editor.commands.setLink({
        href: text,
        target: "_self",
        rel: "",
      });
    }
  }
};
</script>

<template>
  <VDropdown
    class="link-bubble-dropdown"
    :triggers="['click']"
    :distance="10"
    @click="handleLinkBubbleButton"
  >
    <button
      v-tooltip="
        isActive({ editor })
          ? i18n.global.t('editor.extensions.link.edit_link')
          : i18n.global.t('editor.extensions.link.add_link')
      "
      class="link-bubble-button"
      :class="{ 'is-active': isActive({ editor }) }"
    >
      <MdiLinkVariant />
    </button>

    <template #popper>
      <div class="link-bubble-popper">
        <input
          v-model.lazy="href"
          :placeholder="i18n.global.t('editor.extensions.link.placeholder')"
          class="link-input"
        />
        <label class="link-checkbox-label first">
          <input
            v-model="target"
            type="checkbox"
            class="link-checkbox"
          />
          <span class="link-checkbox-text">
            {{ i18n.global.t("editor.extensions.link.open_in_new_window") }}
          </span>
        </label>
        <label class="link-checkbox-label">
          <!-- nofollow -->
          <input
            v-model="rel"
            type="checkbox"
            class="link-checkbox"
          />
          <span class="link-checkbox-text">
            {{ i18n.global.t("editor.extensions.link.nofollow") }}
          </span>
        </label>
      </div>
    </template>
  </VDropdown>
</template>

<style lang="scss" scoped>
.link-bubble-dropdown {
  display: inline-flex;
}

.link-bubble-button {
  border-radius: 0.375rem; // rounded-md
  padding: 0.5rem; // p-2
  font-size: 1.125rem; // text-lg
  color: #4b5563; // text-gray-600

  &:hover {
    background-color: #f3f4f6; // hover:bg-gray-100
  }

  &.is-active {
    background-color: #e5e7eb !important; // bg-gray-200
    color: black !important;
  }
}

.link-bubble-popper {
  position: relative;
  max-height: 18rem; // max-h-72
  width: 24rem; // w-96
  overflow: hidden;
  overflow-y: auto;
  border-radius: 0.375rem; // rounded-md
  background-color: var(--editor-toolbar-bg);
  padding: 0.25rem; // p-1
  box-shadow: var(--editor-box-shadow-light);
}

.link-input {
  display: block;
  width: 100%;
  border-radius: 0.375rem; // rounded-md
  border: 1px solid var(--editor-input-border);
  background-color: var(--editor-input-bg);
  padding: 0.375rem 0.5rem; // px-2 py-1.5
  font-size: 0.875rem; // text-sm
  color: var(--editor-input-text);

  &:hover {
    background-color: var(--editor-button-hover-bg);
  }

  &:focus {
    border-color: var(--editor-input-focus-border);
    outline: none;
    box-shadow: 0 0 0 1px var(--editor-input-focus-border);
  }
}

.link-checkbox-label {
  display: inline-flex;
  align-items: center;
  margin-top: 0.5rem; // mt-2

  &.first {
    margin-right: 0.5rem; // mr-2
  }
}

.link-checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 1rem;
  height: 1rem;
  border-radius: 0.25rem; // rounded
  border: 1px solid var(--editor-input-border);
  background-color: var(--editor-input-bg);
  cursor: pointer;
  position: relative;

  &:focus {
    box-shadow: 0 0 0 1px var(--editor-input-focus-border);
  }

  &:checked {
    background-color: var(--editor-primary-color);
    border-color: var(--editor-primary-color);

    &::after {
      content: "";
      position: absolute;
      left: 0.25rem;
      top: 0.05rem;
      width: 0.35rem;
      height: 0.6rem;
      border: solid white;
      border-width: 0 2px 2px 0;
      transform: rotate(45deg);
    }
  }
}

.link-checkbox-text {
  margin-left: 0.5rem; // ml-2
  font-size: 0.875rem; // text-sm
  color: var(--editor-text-color-secondary);
}
</style>
